<?php
require_once 'Zend/Http/Client/Exception.php';

/**
 * A 'document database' that is really just a binary file repository. It generates unique keys
 * for each file added, however it doesn't allow you to do any kind of versioning.
 *
 * @author Krotscheck
 */
class Core_DocDb_File
{
	/**
	 * Path to the managed directory.
	 *
	 * @var string
	 */
	private $_folder;

	/**
	 * Factory for Core_DocDb_File instances.
	 *
	 * The only argument this factory takes is the absolute path to the directory in which
	 * the documents need to be stored. Usually it deals in paths, allowing a client to retrieve
	 * a path for a given document ID and manipulate it on its own, however in future versions
	 * it may act as an abstraction to the S3 cloud service.
	 *
	 * @param  array $folder
	 * @return Core_DocDb_Files
	 */
	public static function factory ( $config )
	{
		return new Core_DocDb_File($config);
	}

	/**
	 * Constructor. Creates a new instance of a File DB.
	 *
	 * @param  string $folder
	 * @throws Exception
	 */
	public function __construct ( $config )
	{
		if( $config instanceof Zend_Config )
		{
			$config = $config->toArray();
		}
		
		if ( empty($config['folder']) && false == realpath($config['folder']) )
		{
			throw new Core_DocDb_File_Exception('Folder does not exist', 404);
		}
	
		if ( !is_dir($config['folder']) )
		{
			throw new Core_DocDb_File_Exception('Folder is a file, not a directory', 405);
		}
		
		if ( !is_writable($config['folder']) )
		{
			throw new Core_DocDb_File_Exception('Folder is not writable', 403);
		}
		
		// Get the real path
		$this->_folder = realpath($config['folder']);
	}

	/**
	 * Adds a file to the database and assigns a unique key.
	 *
	 * @param File $file
	 * @param boolean $deleteOriginal
	 * @return string
	 */
	public function addFile ( $file, $key = null )
	{
		if ( !file_exists($file))
		{
			throw new Core_DocDb_File_Exception('Source file does not exists', 404);
		}

		if ( is_dir($file))
		{
			throw new Core_DocDb_File_Exception('Cannot include folders', 405);
		}

		if ( $key == null )
		{
			// Create a new unique key
			$key = uniqid( substr(sha1(mt_rand(0,1000)), 0,5) . '_', true);
			$key = str_replace('.', '_', $key);
		}
			
		$filePathInfo = pathinfo($file);
		
		// Generate the file paths.
		$dbPath = $this->getMetadataPath($key);
		$filePath = sprintf('%s/%s.%s', $this->_folder, $key, $filePathInfo['extension']);
		
		// Create the file metadata
		file_put_contents($dbPath, $filePath);
		$success = copy($file, $filePath);
		
		return $key;
	}

	/**
	 * Removes a file from the document database.
	 *
	 * @param string $key
	 * @return boolean
	 */
	public function removeFile ( $key )
	{
		$path = $this->getMetadataPath($key);
		
		if ( !file_exists($path))
		{
			return true;
		}
		
		$sourcePath = file_get_contents($path);
		unlink($sourcePath);
		unlink($path);
	
		return true;
	}

	/**
	 * Returns the absolute path for a given image key.
	 *
	 * @param string $key
	 * @return string
	 */
	public function readFile ( $key )
	{
		$path = $this->getMetadataPath($key);
		
		if ( !file_exists($path))
		{
			throw new Core_DocDb_File_Exception('File not found', 404);
		}
		
		$sourcePath = file_get_contents($path);
		return $sourcePath;
	}
	
	/**
	 * Constructs the metadata path.
	 * 
	 * @param string $key
	 * @return string
	 */
	private function getMetadataPath($key)
	{
		return sprintf('%s/%s.txt', $this->_folder, $key );
	}
}